package Dogtanian;

use strict;
use warnings;

use Module::Load ();
use Exporter;

use odch;

our @ISA = qw(Exporter);
our @EXPORT = qw(say say_as command op_command match every);

our $nick = 'woof';
our $plugin_dir = 'plugins';
our %commands = ();
our %plugins = ();
our %patterns = ();
our %timed_events = ();
my $command_char = '-';

sub nmdc_encode {
	my $text = shift;
	$text =~ s/\$/&\#36;/g;
	$text =~ s/\|/&\#124;/g;
	$text =~ s/\&\#36;/\&amp;\#36;/g;
	$text =~ s/\&\#124;/\&amp;\#124;/g;
	return $text;
}

sub nmdc_decode {
	my $text = shift;
	$text =~ s/&#36;/\$/g;
	$text =~ s/&#124;/\|/g;
	$text =~ s/&amp;#36;/&#36;/g;
	$text =~ s/&amp;#124;/&#124;/g;
	return $text;
}

sub say ($) {
	my $text = shift;
	odch::data_to_all("<$nick> " . nmdc_encode($text) . "|");
}

sub reply (@) {
	odch::data_to_all("<$nick> " . nmdc_encode($::sender . ": " . join ', ', @_) . "|");
}

sub say_as {
	my ($nick,$text) = @_;
	odch::data_to_all("<$nick> " . nmdc_encode($text) . "|");
}

sub load {
	my $plugin_name = shift;
	local $::plugin = $plugin_name;
	print "LOADING $plugin_name\n";
	my $path = $plugin_dir . '/' . $plugin_name . '.pl';
	
	# do this so Perl doesn't think it can get away without
	# reloading
	delete $INC{$path}; 
	require $path;

	print "DONE";
}

sub unload {
	my $plugin_name = shift;
	foreach my $command (keys %{$plugins{$plugin_name}}) {
		delete $commands{$command};
	}
}

sub dispatch {

	my $line = shift;

	local $::sender = $line->{nick};

	my $command = $line->{command};
	my $nick = $line->{nick};
	my $arg = $line->{arg};

	if (not defined $Dogtanian::commands{$command}) {
		say("no such command: " . $command);
	} else {
		$Dogtanian::commands{$command}->($arg);
	}
}

sub check {
	my $line = shift;
	
	foreach my $pattern (keys %patterns) {
		if ($line->{text} =~ $pattern) {
			$patterns{$pattern}->($line->{nick}, $line->{text});
		}
	}
}

sub command (@) {
	my $command_name = shift;
	my $callback = shift;

	$commands{$command_name} = $callback;
	$plugins{$::plugin}->{$command_name} = $callback;
}

sub op_command (@) {
	my $command_name = shift;
	my $callback = shift;

	my $op_callback = sub {
		my $user = shift;
		if (is_op($user)) {
			$callback->(@_);
		}
	};

	$commands{$command_name} = $op_callback;
	$plugins{$::plugin}->{$command_name} = $op_callback;
}

sub match (@) {
	my $pattern = shift;
	my $callback = shift;

	$patterns{$pattern} = $callback;
}

sub every (@) {
	my ($time, $callback) = @_;

	$timed_events{$time} = $callback;
}

sub is_op {
	my $user = shift;
	return odch::check_if_registered($user) > 1;
}

sub is_registered {
	my $user = shift;
	return odch::check_if_registered($user) > 0;
}

sub call (@) {
	my ($method, $command, $arg) = @_;

	Dogtanian::dispatch({
		type => $command,
		command => $command,
		arg => $arg
	});
}

sub try (&) {
	my $action = shift;
	eval {
		$action->();
	};
	say("oops, something went wrong: $@") if $@;
}

sub parse_line {
	my $line = shift;
	if ($line =~ /^<([^>]+)\> $command_char(\S+)\s*(.*)\|$/) {
		return {
			type => 'command',
			nick => $1,
			command => Dogtanian::nmdc_decode($2),
			arg => Dogtanian::nmdc_decode($3)
		};
	}
	elsif ($line =~ /^<([^>]+)\> (.*?)\|$/) {
		return {
			type => 'chat',
			nick => $1,
			text => Dogtanian::nmdc_decode($2)
		};
	}
}


1;
